#ifndef __YSIP2__H__
#define __YSIP2__H__


#ifdef HAVE_CONFIG_H
#include<config.h>
#endif
#include<string>
#include<fstream>
#include<iostream>
#include<sstream>
#include<vector>
#include<algorithm>

#ifdef HAVE_SYS_TYPES_H
#include<sys/types.h>
#endif

#ifdef HAVE_STRING_H
#include<string.h>
#endif

#ifdef HAVE_SYS_SOCKET_H 
#include<sys/socket.h>
#endif

#ifdef HAVE_NETINET_IN_H
#include<netinet/in.h>
#endif

#ifdef HAVE_ARPA_INET_H
#include<arpa/inet.h>
#endif

#include<time.h>


#define MAX_REGION_NAME_LENGTH 48
using namespace std;

typedef struct _YSIP2_IP_INFO YSIP2_IP_INFO;
typedef struct _YSIP2_REGION_INFO YSIP2_REGION_INFO;
#ifdef YSIP2_IP_DATA_ALL
typedef struct _YSIP2_REGION_INFO_EX YSIP2_REGION_INFO_EX;
#endif

typedef struct _YSIP2_IP_INFO{
	unsigned int minip;
	unsigned int maxip;
	int region_id;
#if	defined(YSIP2_IP_DATA_ALL)
	int position;
#endif

#if defined(YSIP2_IP_DATA_ALL)
	_YSIP2_IP_INFO() : minip(0),maxip(0),region_id(0){}
#else
	_YSIP2_IP_INFO() : minip(0),maxip(0),region_id(0), position(0){}
#endif

	friend inline ostream & operator << (ostream &os, YSIP2_IP_INFO & ipInfo) {
		os << "minip: " << ipInfo.minip << endl;
		os << "maxip: " << ipInfo.maxip << endl;
		os << "region_id: " << ipInfo.region_id << endl;
#if defined(YSIP2_IP_DATA_ALL)
		os << "position: " << ipInfo.position << endl;
#endif
		return os;
	}
	YSIP2_IP_INFO & operator = (YSIP2_IP_INFO other) {
		if( minip != other.minip) {
			minip = other.minip;
			maxip = other.maxip;
			region_id = other.region_id;
#if defined(YSIP2_IP_DATA_ALL)
			position = other.position;
#endif
		}	
		return *this;
	}
	YSIP2_IP_INFO & operator = (unsigned int oid) {
		minip = maxip = oid;
		region_id = 0;
#if defined(YSIP2_IP_DATA_ALL)
		position = 0;
#endif
		return *this;
	}
	YSIP2_IP_INFO & operator = (YSIP2_IP_INFO * other) {
		if(minip != other->minip) {
			minip = other->minip;
			maxip = other->maxip;
			region_id = other->region_id;
#ifdef YSIP2_IP_DATA_ALL
			region_id = other->position;
#endif
		}
		return *this;
	}
	YSIP2_IP_INFO & operator << (const string buffer) {
		stringstream ss(buffer);
		ss >> minip >> maxip >> region_id;
#ifdef YSIP2_IP_DATA_ALL
		ss >> position;
#endif
		return * this;
	}
	YSIP2_IP_INFO & operator = (const string buffer) {
		stringstream ss(buffer);
		ss >> minip >> maxip >> region_id;
#ifdef YSIP2_IP_DATA_ALL
		ss >> position;
#endif
		return * this;
	}
	bool operator == (unsigned int ip){
		return minip <= ip && maxip >= ip;
	};
	bool operator > (unsigned int ip) {
		return minip > ip;
	}
	bool operator < (unsigned int ip) {
		return maxip < ip;
	}
} YSIP2_IP_INFO;

typedef struct _YSIP2_REGION_INFO{
	int id;
	int parent_id;
	int parent_pos;
	int level;
	char name[MAX_REGION_NAME_LENGTH]; // through compute got 45  48 = 12 * 4;

	_YSIP2_REGION_INFO():id(0),parent_id(0),parent_pos(0), level(0){
		name[0] = '\0';
	}
	YSIP2_REGION_INFO & operator = (YSIP2_REGION_INFO other) {
		if(id != other.id) {
			id = other.id;
			parent_id = other.parent_id;
			parent_pos = other.parent_pos;
			strncpy(name, other.name, MAX_REGION_NAME_LENGTH);
			level = other.level;
		}
		return * this;
	}
	YSIP2_REGION_INFO & operator = (YSIP2_REGION_INFO * other) {
		if(id != other->id) {
			id = other->id;
			parent_pos = other->parent_pos;
			parent_id = other->parent_id;
			strncpy(name, other->name, MAX_REGION_NAME_LENGTH);
			level = other->level;
		}
		return * this;
	}
	YSIP2_REGION_INFO & operator = (int oid) {
		if(id != oid) {
			id = oid;
			parent_id = 0;
			parent_pos = 0;
			name[0] = '\0';
			level = 0;
		}
		return * this;
	}
	friend inline ostream & operator << (ostream &os, YSIP2_REGION_INFO & regionInfo) {
		os << "id: " << regionInfo.id << endl;
		os << "parent_id: " << regionInfo.parent_id << endl;
		os << "name: " << regionInfo.name << endl;
		os << "parent_pos: " << regionInfo.parent_pos << endl;
		os << "level: " << regionInfo.level << endl;
		return os;
	}

	YSIP2_REGION_INFO & operator << (const string buffer) {
		stringstream ss(buffer);
		ss >> id >> name >> parent_id >> parent_pos >> level;
		return * this;
	}

	YSIP2_REGION_INFO & operator = (const string buffer) {
		stringstream ss(buffer);
		ss >> id >> name >> parent_id >> parent_pos >> level;
		return * this;
	}
	bool operator == (int oid) {
		return id == oid;
	}
	bool operator > (int oid) {
		return id > oid;
	}
	bool operator < (int oid) {
		return id < oid;
	}
} YSIP2_REGION_INFO;

#ifdef YSIP2_IP_DATA_ALL
typedef struct _YSIP2_REGION_INFO_EX : public YSIP2_REGION_INFO {
	string detail;
	_YSIP2_REGION_INFO_EX():detail("") {};

	YSIP2_REGION_INFO_EX & operator = (YSIP2_REGION_INFO other) {
		if(id != other.id) {
			id = other.id;
			parent_id = other.id;
			parent_pos = other.parent_pos;
			level = other.level;
			strncpy(name, other.name, MAX_REGION_NAME_LENGTH);
			detail = "";
		}
		return * this;
	};

	YSIP2_REGION_INFO_EX & operator = (YSIP2_REGION_INFO_EX other) {
		if(id != other.id) {
			id = other.id;
			parent_id = other.id;
			parent_pos = other.parent_pos;
			level = other.level;
			strncpy(name, other.name, MAX_REGION_NAME_LENGTH);
			detail = other.detail;
		}
		return * this;
	};

	friend inline ostream & operator << (ostream &os, YSIP2_REGION_INFO_EX & regionInfo) {
		os << "id: " << regionInfo.id << endl;
		os << "parent_id: " << regionInfo.parent_id << endl;
		os << "name: " << regionInfo.name << endl;
		os << "parent_pos: " << regionInfo.parent_pos << endl;
		os << "level: " << regionInfo.level << endl;
		os << "detail: " << regionInfo.detail << endl;
		return os;	
	}
} YSIP2_REGION_INFO_EX;
#endif


bool ysipInit(const string root = "/var/ysip/");

template <class T>
bool ysipLoadData(const string file, T * array, int &count);

bool ysipGetIpInfo(const string ip, YSIP2_REGION_INFO & regionInfo);
#ifdef YSIP2_IP_DATA_ALL
bool ysipGetIpInfo(const string ip, YSIP2_REGION_INFO_EX & regionInfo);
#endif
bool ysipGetRegionInfo(const int id, YSIP2_REGION_INFO & regionInfo);
bool ysipGetRegionChilds(const int id, vector<YSIP2_REGION_INFO> & childs, bool includeSelf = true);
bool ysipGetRegionParent(const int id, YSIP2_REGION_INFO * regionInfo);
bool ysipGetRegionParents(const int id, vector<YSIP2_REGION_INFO> & parents, bool includeSelf = true);
int ysipGetStat(int type = 0);
#endif

